﻿// -----------------------------------------------------------------------
// <copyright file="TurnsManager.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace B13_Ex02
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class TurnsManager
    {
        private static readonly Random s_RandomChoice = new Random();
        private readonly List<BoardSquarePosition> m_LegalTurns = new List<BoardSquarePosition>();
        private bool m_MustEat = false;

        public TurnsManager(GameBoard i_GameBoard, PlayerInfo i_ActivePlayer, PlayerInfo i_SecondPlayer)
        {
            updateLegalTurnsList(i_GameBoard, i_ActivePlayer, i_SecondPlayer);
        }

        private void updateLegalTurnsListForPassivePlayer(GameBoard i_GameBoard, PlayerInfo i_ActivePlayer, PlayerInfo i_SecondPlayer)
        {
            updateLegalTurnsList(i_GameBoard, i_ActivePlayer, i_SecondPlayer);
        }

        private void updateLegalTurnsList(GameBoard i_GameBoard, PlayerInfo i_ActivePlayer, PlayerInfo i_SecondPlayer)
        {
            // creates list of legal moves for active player
            m_LegalTurns.Clear();

            // creates eat moves list
            for (int i = 0; i < i_GameBoard.Size; i++)
            {
                for (int j = 0; j < i_GameBoard.Size; j++)
                {
                    if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.Color ||
                        i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                    {
                        if (i_ActivePlayer.Direction == (int)ePlayerDirection.PositiveDirection)
                        {
                            // left and down
                            if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j - 2, i, i + 2) == true)
                            {
                                m_MustEat = true;
                                BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 2, i + 2);
                                m_LegalTurns.Add(newPosition);
                            }

                            // right and down
                            if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j + 2, i, i + 2) == true)
                            {
                                m_MustEat = true;
                                BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 2, i + 2);
                                m_LegalTurns.Add(newPosition);
                            }

                            if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                            {
                                // left and up
                                if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j - 2, i, i - 2) == true)
                                {
                                    m_MustEat = true;
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 2, i - 2);
                                    m_LegalTurns.Add(newPosition);
                                }

                                // right and up
                                if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j + 2, i, i - 2) == true) 
                                {
                                    m_MustEat = true;
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 2, i - 2);
                                    m_LegalTurns.Add(newPosition);
                                }
                            }
                        }

                        if (i_ActivePlayer.Direction == (int)ePlayerDirection.NegativeDirection)
                        {
                            // left and up
                            if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j - 2, i, i - 2) == true) 
                            {
                                m_MustEat = true;
                                BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 2, i - 2);
                                m_LegalTurns.Add(newPosition);
                            }

                            // right and up
                            if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j + 2, i, i - 2) == true) 
                            {
                                m_MustEat = true;
                                BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 2, i - 2);
                                m_LegalTurns.Add(newPosition);
                            }

                            if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                            {
                                // left and down
                                if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j - 2, i, i + 2) == true)
                                {
                                    m_MustEat = true;
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 2, i + 2);
                                    m_LegalTurns.Add(newPosition);
                                }

                                // right and down
                                if (isSquareEatable(i_GameBoard, i_SecondPlayer, j, j + 2, i, i + 2) == true)
                                {
                                    m_MustEat = true;
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 2, i + 2);
                                    m_LegalTurns.Add(newPosition);
                                }
                            }
                        }
                    }
                }
            }

            // creates regular moves list if there are no eat moves at all
            if (isEmptyTurnsList() == true)
            {
                for (int i = 0; i < i_GameBoard.Size; i++)
                {
                    for (int j = 0; j < i_GameBoard.Size; j++)
                    {
                        if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.Color ||
                            i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                        {
                            if (i_ActivePlayer.Direction == (int) ePlayerDirection.PositiveDirection)
                            {
                                // left and down
                                if (isSquareOpen(i_GameBoard, j - 1, i + 1) == true) 
                                {
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 1, i + 1);
                                    m_LegalTurns.Add(newPosition);
                                }

                                // right and down
                                if (isSquareOpen(i_GameBoard, j + 1, i + 1) == true) 
                                {
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 1, i + 1);
                                    m_LegalTurns.Add(newPosition);
                                }

                                if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                                {
                                    // left and up
                                    if (isSquareOpen(i_GameBoard, j - 1, i - 1) == true) 
                                    {
                                        BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 1, i - 1);
                                        m_LegalTurns.Add(newPosition);
                                    }

                                    // right and up
                                    if (isSquareOpen(i_GameBoard, j + 1, i - 1) == true) 
                                    {
                                        BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 1, i - 1);
                                        m_LegalTurns.Add(newPosition);
                                    }
                                }
                            }

                            if (i_ActivePlayer.Direction == (int) ePlayerDirection.NegativeDirection)
                            {
                                // left and up
                                if (isSquareOpen(i_GameBoard, j - 1, i - 1) == true) 
                                {
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 1, i - 1);
                                    m_LegalTurns.Add(newPosition);
                                }

                                // right and up
                                if (isSquareOpen(i_GameBoard, j + 1, i - 1) == true) 
                                {
                                    BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 1, i - 1);
                                    m_LegalTurns.Add(newPosition);
                                }
                                
                                if (i_GameBoard.Board[i, j].SquareState == i_ActivePlayer.ColorKing)
                                {
                                    // left and down
                                    if (isSquareOpen(i_GameBoard, j - 1, i + 1) == true) 
                                    {
                                        BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j - 1, i + 1);
                                        m_LegalTurns.Add(newPosition);
                                    }

                                    // right and down
                                    if (isSquareOpen(i_GameBoard, j + 1, i + 1) == true) 
                                    {
                                        BoardSquarePosition newPosition = new BoardSquarePosition(j, i, j + 1, i + 1);
                                        m_LegalTurns.Add(newPosition);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private bool isSquareEatable(GameBoard i_GameBoard, PlayerInfo i_SecondPlayer, int i_ColCurrent, int i_ColNext, int i_RowCurrent, int i_RowNext)
        {
            int colMiddle = (i_ColCurrent + i_ColNext) / 2;
            int rowMiddle = (i_RowCurrent + i_RowNext) / 2;
            return isSquareOpen(i_GameBoard, i_ColNext, i_RowNext) &&
                   isSquareInBounds(i_GameBoard, colMiddle, rowMiddle) &&
                   (i_GameBoard.Board[rowMiddle, colMiddle].SquareState == i_SecondPlayer.Color ||
                    i_GameBoard.Board[rowMiddle, colMiddle].SquareState == i_SecondPlayer.ColorKing);
        }

        private bool isSquareOpen(GameBoard i_GameBoard, int i_Col, int i_Row)
        {
            return isSquareInBounds(i_GameBoard, i_Col, i_Row) &&
                   i_GameBoard.Board[i_Row, i_Col].SquareState == i_GameBoard.Board[i_Row, i_Col].Empty;
        }

        private bool isSquareInBounds(GameBoard i_GameBoard, int i_Col, int i_Row)
        {
            return i_Col >= 0 && i_Col < i_GameBoard.Size && i_Row >= 0 && i_Row < i_GameBoard.Size;
        }

        private bool isEmptyTurnsList()
        {
            bool emptyList = !(m_LegalTurns != null && m_LegalTurns.Count > 0);

            return emptyList;
        }

        public void MakeTurn(GameBoard io_GameBoard, PlayerInfo io_ActivePlayer, PlayerInfo io_PassivePlayer, out string messageToUser, out bool io_IsGameOver, out bool io_LastMoveWasLegal)
        {
            string CurrentMessage = null;
            bool turnPossible = !isEmptyTurnsList();

            bool isLegalChosenMove = io_LastMoveWasLegal = true;

            if (turnPossible == true)
            {
                int selectColNext = 0;
                int selectRowNext = 0;
                int selectColCurrent = 0;
                int selectRowCurrent = 0;
                switch (io_ActivePlayer.IsHuman)
                {
                    case true: // if active player is human, he will be asked to put his next move
                        {
                            selectColNext = io_ActivePlayer.xFuture;
                            selectRowNext = io_ActivePlayer.yFuture;
                            selectColCurrent = io_ActivePlayer.xCurrent;
                            selectRowCurrent = io_ActivePlayer.yCurrent;
                            isLegalChosenMove = isLegalMove(selectColCurrent, selectRowCurrent, selectColNext, selectRowNext);

                            if (isLegalChosenMove == false)
                            {
                                io_LastMoveWasLegal = false;

                                changePlayerActivationToTryAgain(io_ActivePlayer, io_PassivePlayer);
                                if (m_MustEat == false)
                                {
                                    CurrentMessage = string.Format("{0}Illegal Move! Try Again!", Environment.NewLine);
                                }
                                else
                                {
                                    CurrentMessage = string.Format("{0}You must make a jump! Try Again!", Environment.NewLine);
                                }
                            }

                            break;
                        }

                    case false: // if active player is computer, it's next move will be chosen randomly
                        {
                            int computerPlayerChoice = s_RandomChoice.Next(0, m_LegalTurns.Count - 1);
                            selectColCurrent = m_LegalTurns[computerPlayerChoice].ColCurrent;
                            selectRowCurrent = m_LegalTurns[computerPlayerChoice].RowCurrent;
                            selectColNext = m_LegalTurns[computerPlayerChoice].ColNext;
                            selectRowNext = m_LegalTurns[computerPlayerChoice].RowNext;
                            break;
                        }
                }

                if (isLegalChosenMove)
                {
                    makeMove(io_GameBoard, io_ActivePlayer, io_PassivePlayer, selectColCurrent, selectRowCurrent, selectColNext, selectRowNext);
                }

                updateScore(io_GameBoard, io_ActivePlayer, io_PassivePlayer);
            }

            updateLegalTurnsListForPassivePlayer(io_GameBoard, io_PassivePlayer, io_ActivePlayer);
            turnPossible = !isEmptyTurnsList();
            io_IsGameOver = !turnPossible;
            messageToUser = CurrentMessage;
        }

        private void changePlayerActivationToTryAgain(PlayerInfo io_ActivePlayer, PlayerInfo io_PassivePlayer)
        {
                io_ActivePlayer.IsActive = true;
                io_PassivePlayer.IsActive = false;
        }

        private bool isLegalMove(int i_ColCurrent, int i_RowCurrent, int i_ColNext, int i_RowNext)
        {
            bool isMoveLegal = false;
            for (int i = 0; i < m_LegalTurns.Count && !isMoveLegal; i++)
            {
                if (m_LegalTurns[i].ColCurrent == i_ColCurrent && m_LegalTurns[i].RowCurrent == i_RowCurrent &&
                    m_LegalTurns[i].ColNext == i_ColNext && m_LegalTurns[i].RowNext == i_RowNext)
                {
                    isMoveLegal = true;
                }
            }

            return isMoveLegal;
        }

        private void makeMove(GameBoard io_GameBoard, PlayerInfo i_ActivePlayer, PlayerInfo i_SecondPlayer, int i_SelectColCurrent, int i_SelectRowCurrent, int i_SelectColNext, int i_SelectRowNext)
        {
            int squaresDifference = Math.Abs(i_SelectRowNext - i_SelectRowCurrent);

            if ((i_SelectRowNext == (io_GameBoard.Size - 1) || i_SelectRowNext == 0) && (io_GameBoard.Board[i_SelectRowCurrent, i_SelectColCurrent].SquareState != i_ActivePlayer.ColorKing))
            {
                io_GameBoard.Board[i_SelectRowNext, i_SelectColNext].SquareState = i_ActivePlayer.ColorKing;
            }
            
            if (io_GameBoard.Board[i_SelectRowNext, i_SelectColNext].SquareState != i_ActivePlayer.ColorKing)
            {
                io_GameBoard.Board[i_SelectRowNext, i_SelectColNext].SquareState = io_GameBoard.Board[i_SelectRowCurrent, i_SelectColCurrent].SquareState;
            }
            
            io_GameBoard.Board[i_SelectRowCurrent, i_SelectColCurrent].SquareState = io_GameBoard.Board[i_SelectRowCurrent, i_SelectColCurrent].Empty;

            // move is eat
            if (squaresDifference == 2) 
            {
                int middleSquareCol = (i_SelectColCurrent + i_SelectColNext) / 2;
                int middleSquareRow = (i_SelectRowCurrent + i_SelectRowNext) / 2;

                io_GameBoard.Board[middleSquareRow, middleSquareCol].SquareState =
                    io_GameBoard.Board[middleSquareRow, middleSquareCol].Empty;
            }
        }

        private void updateScore(GameBoard i_GameBoard, PlayerInfo io_FirstPlayer, PlayerInfo io_SecondPlayer)
        {
            io_FirstPlayer.Points = 0;
            io_SecondPlayer.Points = 0;
            for (int i = 0; i < i_GameBoard.Size; i++)
            {
                for (int j = 0; j < i_GameBoard.Size; j++)
                {
                    if (i_GameBoard.Board[i, j].SquareState == io_FirstPlayer.Color)
                    {
                        io_FirstPlayer.Points++;
                    }
                    else if (i_GameBoard.Board[i, j].SquareState == io_FirstPlayer.ColorKing)
                    {
                        io_FirstPlayer.Points += 4;
                    }
                    else if (i_GameBoard.Board[i, j].SquareState == io_SecondPlayer.Color)
                    {
                        io_SecondPlayer.Points++;
                    }
                    else if (i_GameBoard.Board[i, j].SquareState == io_SecondPlayer.ColorKing)
                    {
                        io_SecondPlayer.Points += 4;
                    }
                }
            }
        }
    }

    public struct BoardSquarePosition
    {
        private int m_ColNumCurrent;
        private int m_RowNumCurrent;
        private int m_ColNumNext;
        private int m_RowNumNext;

        public BoardSquarePosition(int i_ColCurrent, int i_RowCurrent, int i_ColNext, int i_RowNext)
        {
            m_ColNumCurrent = i_ColCurrent;
            m_RowNumCurrent = i_RowCurrent;
            m_ColNumNext = i_ColNext;
            m_RowNumNext = i_RowNext;
        }

        public int ColCurrent
        {
            get { return m_ColNumCurrent; }
            set { m_ColNumCurrent = value; }
        }

        public int RowCurrent
        {
            get { return m_RowNumCurrent; }
            set { m_RowNumCurrent = value; }
        }

         public int ColNext
        {
            get { return m_ColNumNext; }
            set { m_ColNumNext = value; }
        }

        public int RowNext
        {
            get { return m_RowNumNext; }
            set { m_RowNumNext = value; }
        }
    }
}
